home *** CD-ROM | disk | FTP | other *** search
- #include <iostream.h>
- #include "tserial.h"
- #include <string.h>
- #include <dos.h>
- #include <bios.h>
- #include <conio.h>
-
- // interrupt functions.
- typedef void interrupt far intFunc(...);
-
- // Programmed Interrupt Controller constants.
- const PIC0 = 0x20;
- const PIC1 = 0x21;
- const EOI = 0x20;
-
- // Offsets from port address.
- const InterruptEnable = 1,
- InterruptIdent = 2,
- ModemControl = 4,
- LineStatus = 5,
- ModemStatus = 6;
-
- // Value for the modem control register.
- const ModemControlValue = 11;
-
- // A serial port circular buffer class. There
- // are only two instances of this class, one
- // for each port COM1, and COM2. They are
- // static globals, and are initailized before
- // main(). They contain a circular buffer,
- // the port number and port address, and the
- // interrupt vector they replace, so that
- // they can be restored at destruction. This
- // is not a complete or robust class, and is
- // private to this module. It is intended
- // only for use by SerialStream.
- class ComBuffer {
- public:
- // Size of circular buffer
- enum { BufSize = 0x100 };
- // Default constructor.
- ComBuffer();
- ~ComBuffer();
- // Set up vector, and enables interrupts
- void hookInterrupt();
- // Get a single character from the buffer
- int getc();
- // Send a single character to the port
- void putc(int c);
- // Read the line status register.
- int status() const
- {
- return ::inp(portAddr+LineStatus);
- }
- // Check if characters are available
- int avail() const
- {
- return in != out;
- }
- // Receive a character from port. This function
- // is called by the interrupt routine.
- void receive();
- private:
- // The mask needed for setting the PIC.
- int interruptMask(int port) const
- {
- return 1 << (4 - port);
- }
- // The interrupt number for each port.
- int interruptVec(int port) const
- {
- return 12 - port;
- }
- char *in, *out, *buff; // The circular buffer
- int port; // The port number 0-1
- int portAddr; // The port address
- intFunc *oldVector; // The previos vector
- static int initPort;
- };
-
- // initPort is used by the constructor to initialize
- // the ports in sequence.
- int ComBuffer::initPort = 0;
- // Only two ports are set up here. If you add more
- // you need to identify the port addresses and
- // interrupt vectors.
- static ComBuffer CommPorts[2];
-
- // Initialize the buffers. Allocate the circular
- // buffer, set the in/out pointers, set the port
- // and port address values, and clear the old
- // vector value.
- ComBuffer::ComBuffer()
- : buff(new char[BufSize]), port(initPort++),
- oldVector(0)
- {
- // this line is for sceptics to see initializing.
- cout << "initializing port #" << port << endl;
- portAddr = port ? 0x2f8 : 0x3f8;
- in = out = buff;
- }
-
- // Delete the circular buffer. If the old vector
- // is a valid address, restore it.
- ComBuffer::~ComBuffer()
- {
- // another line for sceptics.
- cout << "de-initializing port #" << port << endl;
- if(oldVector)
- ::setvect(interruptVec(port),oldVector);
- delete[] buff;
- }
-
- // These two routines reset to PIC, and put
- // the new character in the buffer
- void interrupt far comInterrupt0(...)
- {
- ::outp(PIC0,EOI);
- CommPorts[0].receive();
- }
-
- void interrupt far comInterrupt1(...)
- {
- ::outp(PIC0,EOI);
- CommPorts[1].receive();
- }
-
- // This function sets up the interrupts, and
- // enables the PIC
- void
- ComBuffer::hookInterrupt()
- {
- if(oldVector == 0)
- oldVector = ::getvect(interruptVec(port));
- switch(port)
- {
- case 0:
- ::setvect(interruptVec(port),comInterrupt0);
- break;
- case 1:
- ::setvect(interruptVec(port),comInterrupt1);
- break;
- default:
- return;
- }
- ::outp(portAddr+ModemControl,
- ::inp(portAddr+ModemControl)|ModemControlValue);
- ::outp(PIC1,::inp(PIC1) & ~interruptMask(port));
- ::outp(portAddr+InterruptEnable,1);
- ::outp(PIC0, EOI);
- ::inp(portAddr);
- ::inp(portAddr+InterruptIdent);
- ::inp(portAddr+ModemStatus);
- status(); // clear status reg.
- }
-
- // Receive a byte from the port and place in the
- // circular buffer, called from the interrupt
- // handler.
- void
- ComBuffer::receive()
- {
- if(in == buff + BufSize)
- in = buff; // circular buffer
- *in++ = ::inp(portAddr);
- }
-
- // Get a character from the circular buffer.
- int
- ComBuffer::getc()
- {
- while(!avail())
- if(::kbhit())
- return -1;
- if(out == buff + BufSize)
- out = buff; // circular buffer
- return *out++;
- }
-
- // Send a character directly to the port
- void
- ComBuffer::putc(int c)
- {
- while((status() & 0x20) == 0)
- if(::kbhit())
- return;
- ::outp(portAddr, c);
- }
-
- const default_init = _COM_1200|_COM_CHR8|
- _COM_STOP1|_COM_NOPARITY;
-
- // The open function needs to translate the name
- // to the port number, initialize the port, and
- // enable interrupts.
- int SerialStream::open(const char *name, int, int)
- {
- if(::stricmp(name,"COM1") == 0)
- port = 0;
- else if(::stricmp(name, "COM2") == 0)
- port = 1;
- else
- return -1;
- unsigned int stat = ::_bios_serialcom(
- _COM_INIT,port,default_init);
- buffPtr = CommPorts+port;
- buffPtr->hookInterrupt();
- if(stat & 0xFF00)
- return -1;
- return 0;
- }
-
- // The close routine sets the port number to -1
- // to indicate it's closed
- int
- SerialStream::close()
- {
- port = -1;
- return 0;
- }
-
- // The read routine repeatedly calls ComBuffer::getc
- // to fill it's buffer. len should always be 1.
- int SerialStream::read(char *b, size_t len)
- {
- for(int i = 0; i < len; i++)
- b[i] = buffPtr->getc();
- return i;
- }
-
- // The write routine repeatedly calls ComBuffer::putc
- // to empty it's buffer. len should alway be 1.
- int SerialStream::write(char *b, size_t len)
- {
- for(int i = 0; i < len; i++)
- buffPtr->putc(b[i]);
- return i;
- }
-
-